#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "xmalloc.h"
#include "tag.h"
#include "url.h"
#include "dict.h"
#include "array.h"
#include "string.h"
#include "utils.h"

static map_t *url_objects = NULL;


void
init_url_handler(void)
{
  url_objects = hashmap_nnew(URL_MAP_INITSIZ);
}

url_object_t *
url_register(const char *uri, const char *path, const url_type_t type, void *__data)
{
  url_object_t *uo = (url_object_t *) ncmalloc(1, sizeof(url_object_t));
  const char *str_off;

  uo->uri = create_nstring(uri, strnlen(uri, MAX_URL_LEN));
  if ( uri[0] != '/' ) {
    insert_string(uo->uri, 0, "/", 1);
  }
  if ( *(char *)(get_string_off(uo->uri, get_strlen(uo->uri))) == '/' ) {
    del_string(uo->uri, get_strlen(uo->uri), 1);
  }
  uo->path = create_nstring(path, strnlen(path, MAX_URL_LEN));
  switch (type) {
    case URL_BUILTIN:
      str_off = get_string_off(uo->path, get_strlen(uo->path)-strlen(NC_FILE_SUFFIX));
      if (!str_off || strcmp(str_off, NC_FILE_SUFFIX) < 0) {
        add_string(uo->path, "." NC_FILE_SUFFIX);
      }
      uo->data = NULL;
      break;
    case URL_STATIC:
      uo->data = __data;
      if (isdir(path)) {
        add_string(uo->path, "index.html");
      }
      break;
  }
  uo->type = type;
  hashmap_put(url_objects, (char *) get_string(uo->uri), (any_t) uo);
  DD("URL object registered: %s", get_string(uo->path));
  return (uo);
}

void
url_set_unused(url_object_t *obj, void *ptr) {
  obj->__unused = ptr;
}

void
url_free(void)
{
  int idx = 0;
  char *key = NULL;
  url_object_t *uo = NULL;

  while (hashmap_iterate_all(url_objects, &idx, &key, (any_t *) &uo)) {
    if (key && uo) {
      free_string(uo->uri);
      free_string(uo->path);
      ncfree(uo, sizeof(url_object_t));
    }
  }
  hashmap_free(url_objects);
}

string_t *
url_parse_path(const char *doc_request)
{
  string_t *str = create_string(doc_request);

  return (str);
}

url_object_t *
url_get(string_t *parsed_url)
{
  size_t slen = get_strlen(parsed_url);
  url_object_t *uo;
  string_t *tmp = create_dupstring(parsed_url);

  if ( *(char *)(get_string_off(parsed_url, slen-1)) == '/' ) {
    set_fstring(tmp, "%sindex.html", get_string(parsed_url));
    DD("ISDIR: %s -> %s", get_string(parsed_url), get_string(tmp));
  }

  if (hashmap_get(url_objects, (char *) get_string(tmp), (any_t *) &uo) == MAP_OK) {
    DD("%s -> %s -> %s [1]", get_string(parsed_url), get_string(uo->uri), get_string(uo->path));
    goto found;
  } else {
    set_fstring(tmp, "%s.html", get_string(parsed_url));
    if (hashmap_get(url_objects, (char *) get_string(tmp), (any_t *) &uo) == MAP_OK) {
      DD("%s -> %s -> %s [2]", get_string(parsed_url), get_string(uo->uri), get_string(uo->path));
      goto found;
    }
  }
  DD("Invalid URL object: %s", get_string(parsed_url));
  free_string(tmp);
  return (NULL);
found:
  free_string(tmp);
  return (uo);
}

map_t
url_parse_query(const char *query_str)
{
  uint8_t i = 0;
  char *start = NULL, *mid = NULL, *end = NULL;
  map_t result = hashmap_new();

  if ( !(query_str && *(query_str) != '\0') ) return (result);
  start = (char *) query_str;
  do {
    char *key = NULL, *val = NULL;
    if ( (end = (char *) strstr(start, "&")) == NULL )
    {
      end = (char *)(start + strlen(start));
    }
    if ( (mid = strstr(start, "=")) != NULL )
    {
      if (mid < end)
      {
        key = strndup(start, (size_t)(mid-start));
        val = strndup((char *)(mid+1), (size_t)(end - (mid+1)));
      }
    } else {
      key = strdup("action");
      val = strndup(start, (size_t)(end-start));
    }
    if (hashmap_put(result, key, (char *) val) != MAP_OK) {
      free(key);
      free(val);
    }
    i++;
  } while ( (start = (char *)strstr(start + 1, "&")) && *(start+1) != '\0' && start++ && i < MAX_QRY_ARGS);

  return (result);
}

void
url_free_query(map_t *qry)
{
  int idx = 0;
  char *key = NULL, *val = NULL;

  if (!qry) return;
  while (hashmap_iterate_all(*qry, &idx, &key, (any_t *)&val)) {
    free(key);
    free(val);
  }
  hashmap_free(*qry);
  *qry = NULL;
}

